package com.nn.smart.bus.httpclient;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.net.ssl.SSLException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;

/**
 * @author nanning
 * @Date 18-11-27
 */
@Configuration
@EnableConfigurationProperties({HttpClientProperty.class})
public class HttpClientAutoConfigration {

    @Autowired
    private HttpClientProperty httpClientProperty;

    /**
     * HttpClient的重试处理机制
     *
     * @return
     */
    @Bean
    public HttpRequestRetryHandler httpRequestRetryHandler() {
        // 请求重试
        final int retryTime = httpClientProperty.getRetryTime();
        return (exception, executionCount, context) -> {
            // Do not retry if over max retry count,如果重试次数超过了retryTime,则不再重试请求
            if (executionCount >= retryTime) {
                return false;
            }
            // 服务端断掉客户端的连接异常
            if (exception instanceof NoHttpResponseException) {
                return true;
            }
            // time out 超时重试
            if (exception instanceof InterruptedIOException) {
                return true;
            }
            // Unknown host
            if (exception instanceof UnknownHostException) {
                return false;
            }
            // Connection refused
            if (exception instanceof ConnectTimeoutException) {
                return false;
            }
            // SSL handshake exception
            if (exception instanceof SSLException) {
                return false;
            }
            HttpClientContext clientContext = HttpClientContext.adapt(context);
            HttpRequest request = clientContext.getRequest();
            if (!(request instanceof HttpEntityEnclosingRequest)) {
                return true;
            }
            return false;
        };
    }

    /**
     * 连接池管理
     *
     * @return
     */
    @Bean
    public PoolingHttpClientConnectionManager poolingClientConnectionManager() {
        PoolingHttpClientConnectionManager poolHttpcConnManager = new PoolingHttpClientConnectionManager(60, TimeUnit.SECONDS);
        // 最大连接数
        poolHttpcConnManager.setMaxTotal(httpClientProperty.getConnMaxTotal());
        // 路由基数
        poolHttpcConnManager.setDefaultMaxPerRoute(httpClientProperty.getMaxPerRoute());
        return poolHttpcConnManager;
    }

    /**
     * @return
     */
    @Bean
    public RequestConfig requestConfig() {
        return RequestConfig.custom()
                .setConnectionRequestTimeout(httpClientProperty.getConnectRequestTimeout())
                .setConnectTimeout(httpClientProperty.getConnectTimeout())
                .setSocketTimeout(httpClientProperty.getSocketTimeout())
                .build();
    }

    @Bean
    public HttpClientManagerFactoryBen httpClientManagerFactoryBen() {
        return new HttpClientManagerFactoryBen(httpRequestRetryHandler(), poolingClientConnectionManager(), requestConfig());
    }

    @Bean
    public HttpClientUtils httpClientUtils() {
        return new HttpClientUtils(httpClientManagerFactoryBen());
    }

}
